using System;
using System.Numerics;
namespace Meow.Core;

public readonly struct int4 : IEquatable<int4>
{
	public readonly int X, Y, Z, W;
	public int4(int x, int y, int z, int w) { X = x; Y = y; Z = z; W = w; }

	public static int4 operator +(int4 a, int4 b) { return new int4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); }
	public static int4 operator -(int4 a, int4 b) { return new int4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); }
	public static int4 operator *(int a, int4 b) { return new int4(a * b.X, a * b.Y, a * b.Z, a * b.W) ; }
	public static int4 operator *(int4 b, int a) { return new int4(a * b.X, a * b.Y, a * b.Z, a * b.W) ; }
	public static int4 operator /(int4 a, int b) { return new int4(a.X / b, a.Y / b, a.Z / b, a.W / b); }

	public static int4 operator -(int4 a) { return new int4(-a.X, -a.Y, -a.Z, -a.W); }

	public static bool operator ==(int4 me, int4 other) { return me.X == other.X && me.Y == other.Y && me.Z == other.Z && me.W == other.W; }
	public static bool operator !=(int4 me, int4 other) { return !(me == other); }

	public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode(); }

	public bool Equals(int4 other) { return this == other; }
	public override bool Equals(object obj) { return obj is int4 vec && Equals(vec); }

	public override string ToString() { return X + "," + Y + "," + Z + "," + W; }

	public int4 Sign() { return new int4(Math.Sign(X), Math.Sign(Y), Math.Sign(Z), Math.Sign(W)); }
	public int4 Abs() { return new int4(Math.Abs(X), Math.Abs(Y), Math.Abs(Z), Math.Abs(W)); }
	public int LengthSquared => X * X + Y * Y + Z * Z + W * W;
	public int Length => Exts.ISqrt(LengthSquared);

	public int4 WithX(int newX)
	{
		return new int4(newX, Y, Z, W);
	}

	public int4 WithY(int newY)
	{
		return new int4(X, newY, Z, W);
	}

    public int4 WithZ(int newZ)
    {
        return new int4(X, Y, newZ, W);
    }

    public int4 WithW(int newW)
    {
        return new int4(X, Y, Z, newW);
    }

    public static int4 Max(int4 a, int4 b) { return new int4(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Max(a.Z, b.Z), Math.Max(a.W, b.W)); }
	public static int4 Min(int4 a, int4 b) { return new int4(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z), Math.Min(a.W, b.W)); }

	public static readonly int4 Zero = new int4(0, 0, 0, 0);
	public Vector2 ToVector2() { return new Vector2(X, Y); }
	public Vector3 ToVector3() { return new Vector3(X, Y, Z); }
    public Vector4 ToVector4() { return new Vector4(X, Y, Z, W); }

    public static int4 FromVector2(Vector2 vec2) { return new int4((int)vec2.X, (int)vec2.Y, 0, 0); }
	public static int4 FromVector3(Vector3 vec3) { return new int4((int)vec3.X, (int)vec3.Y, (int)vec3.Z, 0 ); }
    public static int4 FromVector4(Vector4 vec4) { return new int4((int)vec4.X, (int)vec4.Y, (int)vec4.Z, (int)vec4.W); }

	public static int4 Lerp(int4 a, int4 b, int mul, int div)
	{
		return a + (b - a) * mul / div;
	}

	public static int Dot(int4 a, int4 b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; }
}
